﻿using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;

namespace KuiHuaBaoDian.Services.Asset {

    public interface IAssetInstantiateParentProvider {

        Transform Parent { get; }
    }

    public interface IAssetRequest {

        public static IAssetRequest Build(string key) {
            return new AssetRequest(key);
        }

        string Key { get; }

        CancellationToken CancellationToken { get; }

        IAssetLoadProgress LoadProgress { get; }

        bool IsIgnoreFailureLog { get; }

        IAssetRequest WithCancellationToken(CancellationToken cancellationToken);

        IAssetRequest WithLoadProgress(IAssetLoadProgress loadProgress);

        IAssetRequest SetIsIgnoreFailureLog(bool isIgnoreFailureLog);

        IAssetRequest IgnoreFailureLog();

        IAssetRequest ReportFailureLog();

        UniTask<AssetHandle<T>> Load<T>(Action<AssetHandle<T>> onComplete = null) where T : UnityEngine.Object;

        UniTask<GameObject> Instantiate(IAssetInstantiateParentProvider parentProvider, bool isActive = true, Action<GameObject> onComplete = null);

        UniTask<GameObject> Instantiate(Transform parent = null, bool isActive = true, Action<GameObject> onComplete = null);
    }

    internal sealed class AssetRequest : IAssetRequest {

        public string Key { get; private set; }

        public CancellationToken CancellationToken { get; private set; }

        public IAssetLoadProgress LoadProgress { get; private set; }

        public bool IsIgnoreFailureLog { get; private set; }

        public AssetRequest(string key) {
            Key = key;
        }

        public IAssetRequest SetIsIgnoreFailureLog(bool isIgnoreFailureLog) {
            IsIgnoreFailureLog = isIgnoreFailureLog;
            return this;
        }

        public IAssetRequest IgnoreFailureLog() {
            IsIgnoreFailureLog = true;
            return this;
        }

        public IAssetRequest ReportFailureLog() {
            IsIgnoreFailureLog = false;
            return this;
        }

        public IAssetRequest WithCancellationToken(CancellationToken cancellationToken) {
            CancellationToken = cancellationToken;
            return this;
        }

        public IAssetRequest WithLoadProgress(IAssetLoadProgress loadProgress) {
            LoadProgress = loadProgress;
            return this;
        }

        public UniTask<AssetHandle<T>> Load<T>(Action<AssetHandle<T>> onComplete = null) where T : UnityEngine.Object {
            return UIOC.Application.Services.Get<IAssetService>().Load<T>(this);
        }

        public UniTask<GameObject> Instantiate(IAssetInstantiateParentProvider parentProvider, bool isActive = true, Action<GameObject> onComplete = null) {
            UnityEngine.Assertions.Assert.IsNotNull(parentProvider);

            return Instantiate(parentProvider.Parent, isActive, onComplete);
        }

        public UniTask<GameObject> Instantiate(Transform parent = null, bool isActive = true, Action<GameObject> onComplete = null) {
            return UIOC.Application.Services.Get<IAssetService>().Instantiate(this, parent, isActive, onComplete);
        }
    }
}